package org.example.rabbitmq;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @author Lenovo
 * @version 1.0
 * @description TODO
 * @date 26/7/2023 上午10:30
 */

@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath:spring-rabbitmq.xml")
public class ProducerTest {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 只发队列消息
     * 默认交换机类型为 direct
     * 交换机的名称为空,路由键为队列的名称
     */
    @Test
    public void queueTest() {
        //路由键与队列同名
        rabbitTemplate.convertAndSend("spring_queue", "只发队列spring_queue的消息。");
    }

    /**
     * 发送广播
     * 交换机类型为 fanout
     * 绑定到该交换机的所有队列都能够收到消息
     */
    @Test
    public void fanoutTest() {
        /**
         * 参数1：交换机名称
         * 参数2：路由键名（广播设置为空）
         * 参数3：发送的消息内容
         */
        rabbitTemplate.convertAndSend("spring_fanout_exchange", "", "发送到spring_fanout_exchange交换机的广播消息");
    }

    /**
     * 通配符
     * 交换机类型为 topic
     * 匹配路由键的通配符,*表示一个单词,#表示多个单词
     * 绑定到该交换机的匹配队列能够收到对应消息
     */
    @Test
    public void topicTest() {
        /**
         * 参数1：交换机名称
         * 参数2：路由键名
         * 参数3：发送的消息内容
         */
        rabbitTemplate.convertAndSend("spring_topic_exchange", "demo.bj", "发送到spring_topic_exchange交换机demo.bj的消息");
        rabbitTemplate.convertAndSend("spring_topic_exchange", "test.bj.1", "发送到spring_topic_exchange交换机test.bj.1的消息");
        rabbitTemplate.convertAndSend("spring_topic_exchange", "www.bj.2", "发送到spring_topic_exchange交换机www.bj.2的消息");
        rabbitTemplate.convertAndSend("spring_topic_exchange", "www.cn", "发送到spring_topic_exchange交换机www.cn的消息");
    }
    @Test
    public void confirmTest(){
        // 定义确认回调函数
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                if (ack){
                    System.out.println("投递成功");
                }else {
                    System.out.println("投递失败");
                    System.out.println("失败的原因是:" + cause);
                    // 处理...
                }
            }
        });
        // 测试确认模式(成功)
        //rabbitTemplate.convertAndSend("test_spring_direct_exchange","confirm","测试确认模式");
        // 失败情况
        rabbitTemplate.convertAndSend("test_spring_direct_exchange1","confirm","测试确认模式");
    }

    @Test
    public void returnTest(){
        // 需要设置强制退回，必须设置
        rabbitTemplate.setMandatory(true);
        //退回模式的回调函数，只有失败才会调用退回模式，与确认不太一样
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingkey) {
                // 获取消息
                System.out.println("new String (message.getBody()) = " + new String(message.getBody()));
                // 错误消息
                System.out.println("replyText = " + replyText);
                // 错误码
                System.out.println("replyCode = " + replyCode);
                // 交换机的名字
                System.out.println("exchange = " + exchange);
                // 路由key
                System.out.println("routingkey = " + routingkey);
            }
        });
        // 测试退回模式(成功)
        //rabbitTemplate.convertAndSend("test_spring_direct_exchange","confirm","测试退回模式");
        // 失败情况
        rabbitTemplate.convertAndSend("test_spring_direct_exchange","confirm1","测试退回模式");
    }

    @Test
    public void ttlTest(){
        // 创建消息的后置处理器
        MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                // 设置消息的有效时间5秒
                message.getMessageProperties().setExpiration("5000");
                return message;
            }
        };
        rabbitTemplate.convertAndSend("test_ttl_exchange","test.add","测试过期时间",messagePostProcessor);
    }
    @Test
    public void dlxTest() {
        //1. 测试过期时间，死信消息
        //rabbitTemplate.convertAndSend("test_exchange_dlx", "test.dlx.haha", "我是一条消息,我会死吗？");

        //2. 测试长度限制后,消息死信
        for (int i = 0; i < 20; i++) {
            rabbitTemplate.convertAndSend("test_exchange_dlx","test.dlx.haha","我是一条消息,我会死吗？");
        }

    }
    @Test
    public  void testDelay() throws InterruptedException {
        //1.发送订单消息。 将来是在订单系统中,下单成功后,发送消息
        rabbitTemplate.convertAndSend("test_exchange_dlx",
                "order.msg","订单信息：id=1,time=2020年10月17日11：41：47");

        //2.打印倒计时10秒
        for (int i = 10; i > 0 ; i--) {
            System.out.println(i+"...");
            Thread.sleep(1000);
        }
    }

}